package com.ydlclass.loadbalance.loadbalancer;

import com.ydlclass.configuration.YrpcConfiguration;
import com.ydlclass.configuration.YrpcConfigurationHolder;
import com.ydlclass.loadbalance.LoadBalancer;
import com.ydlclass.loadbalance.Selector;
import com.ydlclass.message.MetaData;
import com.ydlclass.message.YrpcMessage;
import com.ydlclass.registry.Registry;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author it楠老师
 * @createTime 2023-03-26
 */
@Slf4j
public class RoundRobinLoadBalancer implements LoadBalancer {

    private Map<String, RoundRobinSelector> selectors = new ConcurrentHashMap<>(32);

    @Override
    public InetSocketAddress selectServiceAddress(List<InetSocketAddress> serviceInetSocketAddress, YrpcMessage yrpcMessage) {
        if(yrpcMessage.getPayload() instanceof MetaData metaData) {
            String serviceName = metaData.getInterfaceName();
            RoundRobinSelector roundRobinSelector = selectors.get(serviceName);
            if(roundRobinSelector == null){
                YrpcConfiguration yrpcConfiguration = YrpcConfigurationHolder.get();
                Registry registry = yrpcConfiguration.getRegistry();
                List<InetSocketAddress> serviceList = registry.lookup(serviceName);

                roundRobinSelector = new RoundRobinSelector(serviceList);
                selectors.put(serviceName,roundRobinSelector);
            }
            if(log.isDebugEnabled()){
                log.debug("balancing --> The round robin algorithm is being used for load balancing.");
            }
            return roundRobinSelector.getNext(yrpcMessage);

        }

        return null;
    }


    /**
     * 使用chatGpt生成的轮询算法
     */
    private static class RoundRobinSelector implements Selector {
        private List<InetSocketAddress> serviceList; // 存储服务节点的列表
        private AtomicInteger counter; // 计数器，用于记录当前选中的节点索引

        // 构造函数，传入服务节点列表
        public RoundRobinSelector(List<InetSocketAddress> nodes) {
            this.serviceList = nodes;
            this.counter = new AtomicInteger(0);
        }

        // 获取下一个服务节点
        @Override
        public InetSocketAddress getNext(YrpcMessage yrpcMessage) {
            // 如果节点列表为空，返回null
            if (serviceList == null || serviceList.isEmpty()) {
                return null;
            }

            // 获取当前计数器的值，并增加1
            int currentIndex = counter.getAndIncrement();

            // 如果计数器的值超过整型最大值，重置为0
            if (currentIndex == Integer.MAX_VALUE) {
                counter.set(0);
            }

            // 返回当前索引对应的服务节点，这里使用取模操作，确保索引在节点列表范围内
            return serviceList.get(currentIndex % serviceList.size());
        }

        @Override
        public void reload(String serviceName, List<InetSocketAddress> newServiceList) {

        }

    }
}
